package com.yueyang.sojourn.server.service.sojourn.banner;

import com.yueyang.sojourn.server.common.Services;
import com.yueyang.sojourn.server.common.baymax.web.result.JAssert;
import com.yueyang.sojourn.server.common.consts.Constants;
import com.yueyang.sojourn.server.model.dto.AddBannerDto;
import com.yueyang.sojourn.server.model.dto.EditBannerDto;
import com.yueyang.sojourn.server.model.enums.StatusEnum;
import com.yueyang.sojourn.server.model.po.SojournBanner;
import com.yueyang.sojourn.server.service.attachdetail.AttachDetailService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author yemingxing
 * @summary
 * @Copyright (c) 2020, Yueyang Group All Rights Reserved.
 * @since 2020-02-27 00:57
 */
@Service
@Slf4j
public class WriteBannerService {

    @Autowired
    private SojournBannerService sojournBannerService;
    @Autowired
    private ReadBannerService readBannerService;
    @Autowired
    private AttachDetailService attachDetailService;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 新增banner
     *
     * @param loginUserId
     * @param bannerDto
     */
    public void add(long loginUserId, AddBannerDto bannerDto) {
        if (BooleanUtils.isFalse(readBannerService.positionAvailable(bannerDto.getShowTimeBegin(), bannerDto.getShowTimeEnd(), null))) {
            // todo-ymx 考虑并发场景，在redis中判断
            JAssert.justFailed("该时段展位已无剩余展位");
        }

        // 展位排序加锁10s
        boolean lockResult = redisTemplate.opsForValue().setIfAbsent(Constants.BANNER_SORT_KEY_PERFIX + bannerDto.getSort(), 0, 10, TimeUnit.SECONDS);
        try {
            if (BooleanUtils.isFalse(lockResult)) {
                // 考虑短时并发，先在缓存中判断
                JAssert.justFailed("展位排序值与其他展位排序值重复，请更改");
                return;
            }
            if (BooleanUtils.isFalse(readBannerService.sortAvailable(bannerDto.getSort(), bannerDto.getShowTimeBegin(), bannerDto.getShowTimeEnd()))) {
                JAssert.justFailed("展位排序值与其他展位排序值重复，请更改");
            }
            try {
                Services.of(WriteBannerService.class).addWithTransaction(loginUserId, bannerDto);
            } catch (Exception e) {
                log.error("新增banner失败" + bannerDto, e);
                JAssert.justFailed("系统内部异常");
            }
        } finally {
            redisTemplate.delete(Constants.BANNER_SORT_KEY_PERFIX + bannerDto.getSort());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void addWithTransaction(long loginUserId, AddBannerDto bannerDto) {
        SojournBanner banner = new SojournBanner();
        BeanUtils.copyProperties(bannerDto, banner);
        // 图片
        long attachId = attachDetailService.addReturnId(loginUserId, bannerDto.getPic());
        banner.setAttachId(attachId);
        banner.setStatus(StatusEnum.VALID.getCode());
        Date nowDate = new Date();
        banner.setCreator(loginUserId);
        banner.setCreatedTime(nowDate);
        banner.setUpdator(loginUserId);
        banner.setUpdatedTime(nowDate);
        sojournBannerService.insert(banner);
    }

    /**
     * 编辑banner
     *
     * @param loginUserId
     * @param bannerDto
     */
    public void edit(long loginUserId, EditBannerDto bannerDto) {
        // 展位排序加锁10s
        boolean lockResult = redisTemplate.opsForValue().setIfAbsent(Constants.BANNER_SORT_KEY_PERFIX + bannerDto.getSort(), 0, 10, TimeUnit.SECONDS);
        try {
            if (BooleanUtils.isFalse(lockResult)) {
                // 考虑短时并发，先在缓存中判断
                JAssert.justFailed("展位排序值与其他展位排序值重复，请更改");
                return;
            }
            SojournBanner bannerBefore = sojournBannerService.selectByPrimaryKey(bannerDto.getId());
            if (Objects.isNull(bannerBefore)) {
                JAssert.justFailed("不存在的bannerId:" + bannerDto.getId());
            }
            if (bannerDto.getShowTimeBegin() != null || bannerDto.getShowTimeEnd() != null) {
                JAssert.validParam(Objects.nonNull(bannerDto.getShowTimeBegin()) && Objects.nonNull(bannerDto.getShowTimeEnd()),
                        "展位时间段 不能为空");
                if (BooleanUtils.isFalse(readBannerService.positionAvailable(bannerDto.getShowTimeBegin(), bannerDto.getShowTimeEnd(), Collections.singletonList(bannerDto.getId())))) {
                    JAssert.justFailed("该时段展位已无剩余展位");
                }
                if (bannerDto.getSort() != null && BooleanUtils.isFalse(bannerBefore.getSort().equals(bannerDto.getSort()))) {
                    // 添加新的排序值
                    if (BooleanUtils.isFalse(readBannerService.sortAvailable(bannerDto.getSort(), bannerDto.getShowTimeBegin(), bannerDto.getShowTimeEnd()))) {
                        JAssert.justFailed("此数值与其他展位数值重复，请更改");
                    }
                }
            } else {
                if (bannerDto.getSort() != null && BooleanUtils.isFalse(bannerBefore.getSort().equals(bannerDto.getSort()))) {
                    // 添加新的排序值
                    if (BooleanUtils.isFalse(readBannerService.sortAvailable(bannerDto.getSort(), bannerBefore.getShowTimeBegin(), bannerBefore.getShowTimeEnd()))) {
                        JAssert.justFailed("此数值与其他展位数值重复，请更改");
                    }
                }
            }

            try {
                Services.of(WriteBannerService.class).editWithTransaction(loginUserId, bannerDto);
            } catch (Exception e) {
                log.error("编辑banner失败" + bannerDto, e);
                JAssert.justFailed("系统内部异常");
            }
        } finally {
            redisTemplate.delete(Constants.BANNER_SORT_KEY_PERFIX + bannerDto.getSort());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void editWithTransaction(long loginUserId, EditBannerDto bannerDto) {
        SojournBanner banner = new SojournBanner();
        BeanUtils.copyProperties(bannerDto, banner);
        // 图片
        Long attachId = null;
        if (Objects.nonNull(bannerDto.getPic())) {
            attachId = attachDetailService.addReturnId(loginUserId, bannerDto.getPic());
        }
        banner.setAttachId(attachId);
        Date nowDate = new Date();
        banner.setUpdator(loginUserId);
        banner.setUpdatedTime(nowDate);
        sojournBannerService.updateByPrimaryKeySelective(banner);
    }

    public void delete(long loginUserId, long bannerId) {
        SojournBanner banner = new SojournBanner();
        banner.setId(bannerId);
        banner.setStatus(StatusEnum.INVALID.getCode());
        banner.setUpdator(loginUserId);
        banner.setUpdatedTime(new Date());
        sojournBannerService.updateByPrimaryKeySelective(banner);
    }
}
